use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{parse_macro_input, DeriveInput};

mod gpio;
mod dma;
mod utils;
mod adc;


// ADC1_CH0_CH1_CH2_CH3
#[proc_macro_attribute]
pub fn config_adc(attr: TokenStream, item: TokenStream) -> TokenStream {
    let attr = attr.to_string();
    let input = parse_macro_input!(item as DeriveInput);
    let name = &input.ident;
    let config = adc::parse(&attr);
    let adc = format_ident!("{}", config.name);
    let smp = config.config_smpr();
    let chs = config.create_config_chan();
    let rcc_adc = format_ident!("{}en", config.name.to_lowercase());

    let expand = quote! {
        #input
        impl #name {

            #[inline(always)]
            pub fn init(&self) {
                RCC.apb2enr.modify(|_, w| {
                    w.#rcc_adc().enabled()
                });
                #adc.cr1.write(|w| w.scan().enabled());
                #adc.cr2.write(|w| {
                    w.cont().continuous()
                    .dma().enabled()
                    .dds().continuous()
                });
                #smp
                #adc.cr2.modify(|_, w| {
                    w.adon().enabled()
                });
                #chs
            }

            #[inline(always)]
            pub fn start(&self) {
                #adc.cr2.modify(|_, w| {
                    w.swstart().start()
                });
            }
        }
    };
    TokenStream::from(expand)
}

/**
#[io_group(
    LED1_PA6_OUT_PP,
    LED2_PA7_OUT_PP,
    XX_PC0_AF8_PP_UP
)]
 */
#[proc_macro_attribute]
pub fn config_gpio(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as DeriveInput);
    let name = &input.ident;
    let attr = attr.to_string();
    let sc = gpio::create(&attr);
    let expand = quote! {

        #input

        impl #name {

            #sc
        }
    };

    TokenStream::from(expand)
}

// DMA1_STREAM0_CH0_SIZE8
#[proc_macro_attribute]
pub fn config_dma(attr: TokenStream, item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as DeriveInput);
    let name = &input.ident;
    let attr = attr.to_string();
    let config = dma::Config::parse(&attr);

    let init_rcc = config.init_rcc();
    let clear_flags = config.clear_flags();
    let read_with_circ = config.read_with_circ();
    let write_with_it = config.write_with_it();
    let ndtr = config.ndtr();
    let is_complete = config.is_complete();
    let expand = quote! {
        #input
        impl #name {
            #init_rcc
            #clear_flags
            #read_with_circ
            #write_with_it
            #ndtr
            #is_complete
        }
    };
    TokenStream::from(expand)
}


